package com.jastar.android.game.go;

import java.util.HashSet;
import java.util.Set;

public class GoRules {
    private static final int MODEL = 10;
    private static final int EMPTY = 0;
    private static final int BLACK = 1;
    private static final int WHITE = 2;
    private static final int EMPTY_SPACE = MODEL + EMPTY;
    private static final int BLACK_SPACE = MODEL + BLACK;
    private static final int WHITE_SPACE = MODEL + WHITE;

    private static final int[][] DIRECTIONS = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}}; // 四个方向

    // 检查落子是否合法（考虑提子规则和打劫）
    public static boolean isValidMove(int[][] board, int x, int y, int player) {
        // 检查基本有效性
        if (x < 0 || x >= board.length || y < 0 || y >= board[0].length || board[x][y] != EMPTY) {
            return false;
        }

        // 模拟落子
        int[][] tempBoard = copyBoard(board);
        tempBoard[x][y] = player;

        // 检查是否自杀（没有气）
        if (!hasLiberty(tempBoard, x, y)) {
            // 检查是否能提对方的子
            boolean canCapture = false;
            for (int[] dir : DIRECTIONS) {
                int nx = x + dir[0];
                int ny = y + dir[1];
                if (nx >= 0 && nx < board.length && ny >= 0 && ny < board[0].length && tempBoard[nx][ny] != EMPTY && tempBoard[nx][ny] != player) {
                    if (!hasLiberty(tempBoard, nx, ny)) {
                        canCapture = true;
                        break;
                    }
                }
            }
            if (!canCapture) {
                return false; // 自杀且不能提子，不合法
            }
        }

        return true;
    }

    // 检查一个位置是否有气
    private static boolean hasLiberty(int[][] board, int x, int y) {
        if (board[x][y] == EMPTY) {
            return true; // 空位当然有气
        }

        Set<String> visited = new HashSet<>();
        return checkLibertyDFS(board, x, y, board[x][y], visited);
    }

    // DFS检查气
    private static boolean checkLibertyDFS(int[][] board, int x, int y, int player, Set<String> visited) {
        String key = x + "," + y;
        if (visited.contains(key)) {
            return false;
        }
        visited.add(key);

        for (int[] dir : DIRECTIONS) {
            int nx = x + dir[0];
            int ny = y + dir[1];

            if (nx >= 0 && nx < board.length && ny >= 0 && ny < board[0].length) {
                if (board[nx][ny] == EMPTY) {
                    return true; // 找到气
                } else if (board[nx][ny] == player) {
                    if (checkLibertyDFS(board, nx, ny, player, visited)) {
                        return true;
                    }
                }
            }
        }
        return false;
    }

    // 提子操作
    public static void captureStones(int[][] board, int x, int y, int player) {
        // 模拟落子
        int[][] tempBoard = copyBoard(board);
        tempBoard[x][y] = player;

        // 检查周围四个方向的对方棋子
        for (int[] dir : DIRECTIONS) {
            int nx = x + dir[0];
            int ny = y + dir[1];
            if (nx >= 0 && nx < board.length && ny >= 0 && ny < board[0].length && tempBoard[nx][ny] != EMPTY && tempBoard[nx][ny] != player) {
                // 如果对方棋子没有气，提子
                if (!hasLiberty(tempBoard, nx, ny)) {
                    captureGroup(board, nx, ny, tempBoard[nx][ny]);
                }
            }
        }
    }

    // 提走一组相连的棋子
    private static void captureGroup(int[][] board, int x, int y, int player) {
        if (board[x][y] != player) {
            return;
        }

        board[x][y] = EMPTY;

        for (int[] dir : DIRECTIONS) {
            int nx = x + dir[0];
            int ny = y + dir[1];
            if (nx >= 0 && nx < board.length && ny >= 0 && ny < board[0].length && board[nx][ny] == player) {
                captureGroup(board, nx, ny, player);
            }
        }
    }

    // 复制棋盘
    private static int[][] copyBoard(int[][] board) {
        int[][] copy = new int[board.length][board[0].length];
        for (int i = 0; i < board.length; i++) {
            System.arraycopy(board[i], 0, copy[i], 0, board[i].length);
        }
        return copy;
    }

    // 计算得分
    public static int[] calculateScore(int[][] board) {
        int blackScore = 0;
        int whiteScore = 0;

        updateTerritory(board);

        for (int i = 0; i < board.length; i++) {
            for (int j = 0; j < board[0].length; j++) {
                if (board[i][j] % MODEL == BLACK) {
                    blackScore++;
                } else if (board[i][j] % MODEL == WHITE) {
                    whiteScore++;
                }
            }
        }

        // 黑方贴目，19*19贴3.75，13*13贴2.5，这里简化一下，贴2
        blackScore -= 2;

        return new int[]{blackScore, whiteScore};
    }

    public static void updateTerritory(int[][] board) {
        for (int i = 0; i < board.length; i++) {
            for (int j = 0; j < board[0].length; j++) {
                if (board[i][j] == BLACK || board[i][j] == WHITE) {
                    for (int[] dir : DIRECTIONS) {
                        int nx = i + dir[0];
                        int ny = j + dir[1];
                        if (nx < 0 || nx >= board.length || ny < 0 || ny >= board[0].length) continue;
                        if (board[nx][ny] == EMPTY) setAndSpreadSpace(board, nx, ny, MODEL + board[i][j]);
                    }
                }
            }
        }
    }

    private static void setAndSpreadSpace(int[][] board, int x, int y, int sign) {
        board[x][y] = sign;
        for (int[] dir : DIRECTIONS) {
            int nx = x + dir[0];
            int ny = y + dir[1];
            if (nx < 0 || nx >= board.length || ny < 0 || ny >= board[0].length) continue;
            int nv = board[nx][ny];
            if (sign == EMPTY_SPACE && (nv == EMPTY || nv == BLACK_SPACE || nv == WHITE_SPACE)) {
                setAndSpreadSpace(board, nx, ny, sign);
            }
            if (sign == BLACK_SPACE || sign == WHITE_SPACE) {
                if (nv == EMPTY) {
                    setAndSpreadSpace(board, nx, ny, sign);
                } else if ((nv % MODEL == BLACK || nv % MODEL == WHITE) && sign % MODEL != nv % MODEL) {
                    setAndSpreadSpace(board, x, y, EMPTY_SPACE);
                    break;
                }
            }
        }
    }

    public static String formatString(int[][] board) {
        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < board.length; i++) {
            for (int j = 0; j < board[0].length; j++) {
                builder.append(String.format("%2d,", board[j][i]));
            }
            builder.append("\n");
        }
        return String.valueOf(builder);
    }

}